/**
 * 
 */
package escalonador;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

/**
 * Classe responsavel por fazer a troca de processos.
 * 
 * <p>
 * <h6><i>Esta classe e as demais classes desse pacote foram implementadas como resolucao ao EP1 de SO em 2011</i><br>
 * <b>EACH Turma 04 - USP - Prof. Norton T. Roman</h6></p>
 * 
 * @author Barbara Barbosa Silva
 * @author Daniel Tsuha
 * @author Felipe Sa de Mello
 * @author Lucas Machado
 */
public class Escalonador {

	/**
	 * {@link ArrayList} de {@link BCP} contendo todos os processos.
	 */
	ArrayList<BCP> tabelaProcessos;

	/**
	 * {@link Queue} de {@link BCP} contendo todos os processos prontos.
	 */
	Queue<BCP> processosProntos;

	/**
	 * {@link Queue} de {@link BCP} contendo todos os processos bloqueados.
	 */
	Queue<BCP> processosBloqueados;

	/**
	 * Popula as tabelas com os dados do processo.
	 * 
	 * Procura os arquivos no diretorio raiz da execucao do programa.
	 * 
	 * @throws Exception
	 *             geral caso haja alguma excecao
	 */
	public Escalonador() throws Exception {
		this.processosProntos = Util.carregaProcessos();
		this.processosBloqueados = new LinkedList<BCP>();
		this.tabelaProcessos = new ArrayList<BCP>();

		for (BCP processo : this.processosProntos) {
			this.tabelaProcessos.add(processo);
		}

		if (tabelaProcessos.size() < 1) {
			System.err.println("Tabela de processos vazia! Nenhum processo carregado");
			System.exit(1);// sistema acaba devolvendo 1 para o SO, que eh um
							// status de erro
		}
	}

	/**
	 * Atualiza o tempo de espera de um processo que fez uma requisicao de E/S
	 * (bloqueado).
	 * 
	 * Caso o tempo de espera acabe, o processo eh liberado e incluido na fila
	 * de processos prontos
	 */
	void atualizaListas() {
		Iterator<BCP> it = this.processosBloqueados.iterator();
		while (it.hasNext()) {
			BCP processo = (BCP) it.next();
			if (processo.latencia > 0) {
				processo.latencia--;
			}
		}

		it = this.processosBloqueados.iterator();
		while (it.hasNext()) {
			BCP processo = (BCP) it.next();
			if (processo.latencia == 0) {
				processo.estado = Util.statusProcesso.PRONTO;
				this.processosProntos.add(processo);
				it.remove();
			}
		}
	}

	/**
	 * Metodo principal.
	 * 
	 * @param args
	 *            Array de {@link String} contendo no indice 0 o tamanho do
	 *            Quantum.
	 * @throws Exception
	 *             geral, caso haja alguma excecao durante a execucao
	 */
	public static void main(String[] args) throws Exception {
		int quantum = Integer.parseInt(args[0]);

		File directory = new File("logfiles/" + Integer.toString(quantum));
		directory.mkdirs();
		File logFile = new File(directory, "logfile.txt");
		FileOutputStream outputStream = new FileOutputStream(logFile, true);
		Logger.writer = new PrintStream(outputStream);

		Escalonador escalonador = new Escalonador();
		Processador processador = new Processador(quantum);
		RoundRobin roundRobin = new RoundRobin(escalonador, processador);
		roundRobin.executar();

		Logger.writer.close();
	}
}